require "animloader.rb"

module Dataparse

#A generic Datafile is a comma and linebreak delimited file used to store lists of data. The format is meant to be as compact as possible, while remaining easily editable.
#Each line of the file is an element, and each comma-delimited item is an atribute of its element. A hash/number sign anywhere on a line comments the entire line.
#Datafiles are parsed via iterators. Each iteration yeilds an array containing all of the attributes of a signle element. Datafile#each(values) is the primary iterator used for this purpose.

class DataFile
  attr_reader :file
  
  def each(values=-1)
    @file.reopen(@file.path)
    args = []
    line = ""
    while not @file.eof?
      args = []
      line=@file.readline(); line.strip!
      if line.index("#")==nil
        line=replaceVariables(line)
        line.split(",").each() {|str| args.push(str)}
        args.each() {|str| str.strip!}
      end
      if values!=-1 and args.size<values
        yield(false)
      else
        yield(args)
      end
    end
    @file.close
  end
  
  def replaceVariables(string)
    string.gsub!(/%filename%/i,File.expand_path(@file.path))
    string.gsub!(/%filedir%/,File.dirname(File.expand_path(@file.path)))
    string.subVars!
    return string
  end
  
  def DataFile.parsefunc(text,name,func="anim")
    if text.slice(0,4)==func
      if text.slice(4,1)=="("
        text.gsub!("(","")
        text.gsub!(")","")
        $flog.debug("Environment::Load::ParseAnim") {"Script Parser: Sucessfully preparsed #{func}() for #{name}."}        
      else
        $flog.error("Environment::Load::ParseAnim") {"Script Parser: Bad format for \'#{func}\' function."}
        text="null.png"
      end
    end
    if text=="null.png"
      $flog.warn("Environment::Load::ParseAnim") {"Setting image to default for \'#{name}.\'"}
    end
    return text
  end

  def setFile(file)
    if @file!=nil and not @file.closed?
      @file=File.new(file)
      @file.close
      return true
    else
      return false
    end
  end
  
  def initialize(file="null.rb")
    @file=File.new(file)
    @file.close
  end
end

#SpeechScript is the class which represents all character dialogue scripts. SpeechScripts can be easily integrated with Ruby plugins (See the RubyScript class).
#Speech scripts are only compatible with the TextBar class. See the Text Script Tutorial for more info.

class SpeechScript
  MemStore="scripts/text/sys/store.dat"
  OMemStore="scripts/text/sys/oldstore.dat"
  Week = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
  Month = ["","January","February","March","April","May","June","July","August","September","October","November","December"]
  attr_reader :vars, :file, :hold
  def initialize(file)
    @file=File.new(file)
    @file.close
    @hold=false
    @askQue=Array.new(0) #not actually a queue any more
    @vars={}
    @cleanrun=true #wipe old session before running
  end  
  
  def setFile(file)
    if @file!=nil and not @file.closed?
      @file=File.new(file)
      @file.close
      @vars["*filename*"]=File.expand_path(@file.path)
      return true
    else
      return false
    end
  end
  
  def run #main parsing loop
    @file.reopen(@file.path)
    if @cleanrun
      line = ""
      @pos=0
      @iflevel=0
      @skipif=false
      @ifdone=false
      @labels={}
      @vars={}
      setglobals
      loadstore
      @ingosub=false
      @insubdef=false
      @substack=[]
      @hold=false
      File.copy(MemStore,OMemStore)
    else
      seek(@pos)
    end
    while not @file.eof? and not @hold
      line=@file.readline(); line.strip!;
       # puts line
       # gets
      @pos+=1
      if line.index("#")==nil and line!=""
        line=replaceVariables(line)
        if line.index(" ")!=nil and line.slice(0,1)!="\""
          cmd=line.slice(0,line.index(" "))
          args=line.slice(line.index(" "),line.length-line.index(" "))
          args=splitArgs(args)
        else
          cmd=line
          args=[]
        end
        parse(cmd.strip,args,line)
      end
    end
    @hold=false
    @file.close
  end
  
  def replaceVariables(string)
    string.gsub!(/%filename%/i,File.expand_path(@file.path))
    string.gsub!(/%filedir%/,File.dirname(File.expand_path(@file.path)))
    string.subVars!
    @vars.each { |key,value|
      string.gsub!(key,"\""+value+"\"")
    }
    return string
  end
  
  def splitArgs(args)
    array=[]
    args.strip!
    if args.index(" ")!=nil
      args.sub!(" as ","SYS-SEPERATORasSYS-SEPERATOR")
      args.sub!(" \"","SYS-SEPERATOR\"")
      args.sub!("\" ","\"SYS-SEPERATOR")
      args.sub(" &","&SYS-SEPERATOR")
      args.sub("& ","SYS-SEPERATOR&")
      array=args.split("SYS-SEPERATOR")
      array.each { |arg|
        arg.strip!
      }
    else
      array[0]=args
    end
    return array
  end
  
  def setglobals
    @vars["*filename*"]=File.expand_path(@file.path)
    @vars["*playerid*"]=$window.player.name
    @vars["*playername*"]=$window.player.dispName
    @vars["*day*"]=Week[Time.new.wday]
    @vars["*date*"]=Time.new.day.to_s
    @vars["*month*"]=Month[Time.new.month]    
    @vars["*time*"]=Time.new.to_s    
  end
  
  def loadstore
    store=File.new(MemStore,"r")
    array=[]
    store.each { |entry|
      array=entry.split("\t")
      if array.size>=2
        @vars[array[0].strip]=array[1].strip.split("\"")[0]
      end
    }
    store.close
  end
  
  def skipIf(cmd, args, line)
    if cmd=="elseif"
      if @iflevel==0
        OPlaceIf.error(@file.path, @pos, "elseif")
        return
      end
      if @skipif
        if args.size >= 3
          if args[1] == "="
            if args[0] == args[2]
              @skipif=false
            else
              @skipif=true
            end
          elsif args[1] == "!="
            if args[0] != args[2]
              @skipif=false
            else
              @skipif=true
            end
          else
            LogicToken.error(@file.path, @pos, args[1])
          end
        else
          IfArgs.error(@file.path, @pos)
          IgnoringLine.error(@file.path, @pos)
        end
      else
        @skipif=true
      end
    elsif cmd=="else"
      if @iflevel==0
        OPlaceIf.error(@file.path, @pos, "else")
        return
      end
      if @skipif
        @skipif=false
      else
        @skipif=true
      end
    elsif cmd == "endif"
      @skipif=false
      @iflevel-=1
    end
  end
  
  def parse(cmd,args,line) #parse a single line
    if @insubdef
      if cmd=="return" or cmd=="endsub"
        @insubdef=false
      end
      return
    end
    if @ifdone
      if cmd=="endif"
        if @iflevel==0
          OPlaceIf.error(@file.path, @pos, "endif")
        else
          @iflevel-=1
          @skipif=false
          @ifdone=false
        end
      end
      return
    end
    if @iflevel>0 and @skipif
      skipIf(cmd, args, line)
      return
    end
    if cmd=="show" or cmd=="prime"
      $textbar.wakeUp
    elsif getString(line,0)
      $textbar.queAction(TextBar::TextAction.new(getString(line,0)))
      puts TextBar::TextAction.new(getString(line,0))
    elsif cmd=="end"
      @hold=true
    elsif cmd=="goto" and getString(args[0],0)
      lbl=getString(line,5)
      if lbl==false
        return
      end
      if @labels[lbl]!=nil
        seek(@labels[lbl])
        @pos=@labels[lbl]
      else
        BadGoto.error(@file.path, @pos, lbl)
        IgnoringLine.warn(@file.path, @pos) 
      end
    elsif cmd=="gosub" and getString(args[0],0)
      lbl=getString(args[0],0)
      if @labels[lbl]!=nil
        @substack.push(@pos)
        @ingosub=true
        seek(@labels[lbl])
        @pos=@labels[lbl]
      else
        BadGosub.error(@file.path, @pos, lbl)
        IgnoringLine.warn(@file.path, @pos)  
      end       
    elsif cmd=="sub"
      @labels[getString(args[0],0)]=@pos
      @insubdef=true
    elsif cmd=="return" or cmd=="endsub"
      if @ingosub==true
        seek(@substack.last)
        @pos=@substack.last
        @substack.pop
        if @substack.size==0
          @ingosub=false
        end
      else
        BadReturn.error(@file.path, @pos)
        IgnoringLine.warn(@file.path, @pos)  
      end
    elsif cmd=="def"
      if args[1]!="as"
        NoAs.error(@file.path, @pos)
        IgnoringLine.warn(@file.path, @pos)               
        return
      end
      var=getVar(args[0],0)
      if var==false
        return
      end
      val=getString(args[2],0)
      if val==false
        return
      end
      @vars["*"+var+"*"]=val;
    elsif cmd=="save"
      var=getVar(args[0],0)
      if var==false
        return
      elsif @vars["*"+var+"*"]==nil
        UndefinedVar.error(@file.path, @pos, "*"+var+"*")
        IgnoringLine.warn(@file.path, @pos)          
      else
        store=File.new(MemStore,"a")
        store.write("&"+var+"&\t\""+@vars["*"+var+"*"]+"\"\n")
        store.close
      end
    elsif cmd=="del" and getVar(args[0],0)
      var=getVar(args[0],0)
      var="&"+var+"&"
      store=File.new(MemStore,"r")
      storestr=""
      tstore.each { |entry|
        if entry.strip.split("\t")[0]!=var
          storestr+=entry+"\n"
        end
      }
      store.close
      store=File.new(MemStore,"w")
      store.write storestr
      store.close
      storestr=""
    elsif cmd=="clearstore"
      store=File.new(MemStore,"w")
      store.close
    elsif cmd=="script"
      if args.size >=1 and getString(args[0],0)
        RubyScript.new(args[0]).run
      else
        ScriptArgs.error(@file.path, @pos)
        IgnoringLine.warn(@file.path, @pos)   
      end
    elsif cmd=="ask"
      if args.size >= 3
        yes=getString(args[1],0)
        no=getString(args[2],0)
        $textbar.queAction(TextBar::AskAction.new(getString(args[0],0)))
        $textbar.queAction(TextBar::ReplyAction.new)
        queAsk(yes,no)
      elsif args.size==1
        yes=nil
        no=nil
        $textbar.queAction(TextBar::AskAction.new(getString(args[0],0)))
      else
        AskArgs.error(@file.path, @pos)
        IgnoringLine.error(@file.path, @pos)      
      end
    elsif cmd=="img"
      if args.size>=1
        $textbar.queAction(TextBar::SetImageAction.new(getString(args[0],0)))
      else
        ImgArgs.error(@file.path, @pos)
        IgnoringLine.error(@file.path, @pos)
      end
    elsif cmd=="if"
      if args.size >= 3
        @iflevel+=1
        if args[1] == "="
          @skipif = ( args[0] != args[2] )
        elsif args[1] == "!="
          @skipif = ( args[0] == args[2] )
        else
          LogicToken.error(@file.path, @pos, args[1])
        end
      else
        IfArgs.error(@file.path, @pos)
        IgnoringLine.error(@file.path, @pos)
      end
    elsif cmd=="elseif" or cmd=="else"
      if @iflevel>0 and not @skipif
        @ifdone=true
      else
        OPlaceIf.error(@file.path, @pos, cmd)
      end
    elsif cmd=="endif"
      if @iflevel==0
        OPlaceIf.error(@file.path, @pos, "endif")
      else
        @iflevel-=1
        @skipif=false
        @ifdone=false
      end
    elsif cmd=="action"
      $textbar.queAction(TextBar::SScriptAction.new(getString(args[0],0)))
    else
      BadCommand.error(@file.path, @pos, cmd)
      IgnoringLine.warn(@file.path, @pos)   
    end
  end
  
  def seek(ln)
    @file.seek(0)
    ln.times {
      @file.readline
    }
  end
  
  def getString(line,at) #extract a string from a line
    if line==nil
      return false
    end
    if line[at,1]=="\""
      return basicGetString("\"",line)
    else
      return false
    end
  end
  
  def getVar(line,at)
    if line==nil
      return false
    end
    if line[at,1]=="&"
      var = basicGetString("&",line)
      return var.strip
    else
      ExpectedVar.error(@file.path, @pos) 
      return false
    end         
  end
  
  def basicGetString(delim,line) #extract a string from the specified delimeters
    string=line.split(delim)
    if not line.index(delim,line.index(delim)+1)
      ExpectedEndQuote.error(@file.path, @pos)       
      return false
    end
    string.shift #split error patch
    if string.size==0
      UnknownError.error(@file.path, @pos) 
      return false
    elsif string.size>1
      ExtraChars.warn(@file.path, @pos) 
      return false
    else
      return string[0]
    end
  end
  
  def queAsk(yes,no)
    @askQue[0]=yes
    @askQue[1]=no 
    @hold=true
  end
  
  def respondToAsk(ans)
    @file.reopen(@file.path)
    if ans
      if @labels[@askQue[0]]
        @substack.push(@pos)
        @ingosub=true
        seek(@labels[@askQue[0]])
        @pos=@labels[@askQue[0]]
      else
        BadYesSub.error(@file.path, @pos, @askQue[0])
      end
    else
      if @labels[@askQue[1]]
        @substack.push(@pos)
        @ingosub=true
        seek(@labels[@askQue[1]])
        @pos=@labels[@askQue[1]]
      else
        BadNoSub.error(@file.path, @pos, @askQue[1])
      end
    end
    @askQue.clear
    #@hold=false
    @cleanrun=false
    run
    @cleanrun=true
  end
    
  def each(values=-1) #does nothing
  end
end

#RubyScript is the class which represents Ruby plugins. It run scripts in a sandbox, preventing malicious use, and it also provides utilites for the scripts to interface with the program.
#There is currently no extensive documentation for RubyScripts; they are a work in progress.

class RubyScript
   attr_reader :file
  
  def run(safe=0, wrap=false, join=true)
    safe.untaint
    wrap.untaint
    @file.untaint
    #$flog.close
  begin
    $Utils=Utils.new(@file.path).untaint
    t=Thread.start(File.expand_path(@file.path)) { |path|
      path.untaint
      $SAFE=safe
      load(path,wrap)
    }
    t.join if join
  rescue
  #    $flog=Logger.new('logs/log.txt', 'daily')
      $flog.error("RubyScript:"+@file.path+":RubyError:") { $!.to_s+":\n"+$@.to_s.gsub(":in ",":\nin ") }
  ensure
    if $debug
      $Utils.PrintAll
    end
  end
  #$flog=Logger.new('logs/log.txt', 'daily')
    return t
  end
  
  def initialize(file="null.rb")
    if File.file?(file)
      @file=File.new(file)
      @namespace=@file.path.gsub(" ","_")
      @file.close
    else
      $flog.error("RubyScript") { "'#{file}' does not exist" }      
      $flog.fatal("RubyScript:#{file}") { "Failed to open script" }      
      raise
    end
  end
  
  def setFile(file)
    if @file!=nil and not @file.closed?
      @file.close
    end
    if File.file?(file)
      @file=File.new(file)
      @namespace=@file.path.gsub(" ","_")
      @file.close
      return true
    else
      return false
    end
  end

#Utils is the interface between a RubyScript and the main program.
#Utils allows for the following:
# * Communicating with any currently executing SpeechScript
# * Script parameters
# * Saving and reading data (To circumvent the fact that file access is forbidden.)
# * Registering for runtime event hooks
class Utils
  MemStore="scripts/ruby/sys/store.dat"
  OMemStore="scripts/ruby/sys/oldstore.dat"
  @@globalparameters={}
  @@eventreg = { "Env Load" => [], "Shut Down" => [] , "Render Frame" => [], "Map Init" => []}
  
  def initialize(file, namespace="Global")
    @file=file
    @namespace=namespace
    @parameters=@@globalparameters
    @parameters["Path"]=File.expand_path(@file)
    @parameters["CallPath"]=@file
    @printque=[]
  end
  
  def Parameters(param=nil)
    if param==nil
      return @parameters
    end
    return @parameters[param]
  end
  def SetParameter(key,value)
    @parameters[key]=value
  end
  def Utils.GlobalParameters(param=nil)
    if param==nil
      return @parameters
    end
    return @parameters[param]
  end
  def Utils.SetGlobalParameter(key,value)
    @@globalparameters[key]=value
    # if key=="Event"
    #   RunEvent(value)
    # end
  end
  def Utils.RunEvent(event)
    r=RubyScript.new
    if event=="Plugin Init"
      Dir.new("scripts/ruby/plugins").each { |path|
        if File.file?(path)
          r.setFile(path)
          $flog.info("Plugin Manager") {"Initializing plugin \"#{path}\""}
          r.run
        end
      }
      return true
    elsif event=="Start Up"
      Dir.new("scripts/ruby/startup").each { |path|
        if File.file?(path)
          r.setFile(path)
          $flog.info("Ruby Script") {"Running Start up scripts"}
          r.run
        end
      }
      return true
    elsif @@eventreg[event] != nil
      @@globalparameters["Event"]=event
      s=RubyScript.new
      @@eventreg[event].each { |script|
        if s.setFile(script)
          s.run
        end
      }
      @@globalparameters={}
      return true
    else
      return false
    end
  end
  def Utils.RegisterEvent(scriptname,event)
    if not @@eventreg[event]==nil
      @@eventreg[event].push(scriptname)
      return true
    else
      return false
    end
  end
  def Utils.NewEvent(event)
    if @@eventreg[event]==nil
      @@eventreg[event]=[]
      return true
    else
      return false
    end    
  end
  def Store(key,value,wlock=false,rlock=false,sharewith=[])
    if key.index("\f\t\b") or value.index("\f\t\b")
      return false
    end
    sharewith.each { |item|
      if item.index("\f\t\b") or item.index("\v\t\b")
        return false
      end
    }
    if key.index("::")
      key="Global::"+key
    else 
      key=@namespace+"::"+key
    end
    return false if Read(key)!=nil
    f=File.new(MemStore,"a")
    f.write(key+"\f\t\b"+value+"\f\t\b"+wlock.to_s+"\f\t\b"+rlock.to_s+"\f\t\b")
    if wlock or rlock
      sharewith << File.expand_path(@file)
      sharewith.each { |item|
        f.write(item+"\v\t\b")
      }
    end
    f.write("\n")
    f.close
    return true
  end  
  private
  def getReadVal(arry)
    if arry[3]=="true"
      sharewith=arry[4].split("\v\t\b")
      sharewith.each("\v\t\b") {|script|
        if script==@file or File.expand_path(@file)
          return arry[1]
        end
      }
      return false
    else
      return arry[1]
    end
  end
  public
  def Read(key)
    if key.index("\f\t\b")
      return false
    end
    key=@namespace+"::"+key unless key.index("::")
    f=File.new(MemStore,"r")
    arry=[]
    f.each {|line|
      arry=line.split("\f\t\b")
      if arry[0] == key
        f.close
        return getReadVal(arry)
      end
    }
    f.close
    return nil
  end
  def Namespace(newname=nil)
    if namespace==nil or namespace==""
      return @namespace
    end
    @namespace="Global::"+newname
    return @namespace
  end
  def QuePrint(text)
    @printque.push(text)
  end  
  alias QueuePrint QuePrint 
  def PrintAll
    @printque.each { |item|
      print item
    }
  end
  
  class SpeechScript
    def SpeechScript.Script
      return $textbar.script
    end
    def SpeechScript.Var(var,val)
      if val!=nil
        if $textbar.script.vars[var]
          $textbar.script.vars[var]=val.to_s
          return true
        else
          return false
        end
      elsif var!=nil
        if $textbar.script.vars[var]
          return $textbar.script.vars[var]
        else
          return false
        end
      else
        return $textbar.script.vars
      end
    end
    def SpeechScript.GoSub(sub)
      if sub.index("#")==nil
        if $textbar.script.replaceVariables(sub)!=sub
          sub=$textbar.script.replaceVariables(sub)
        else
          sub="\""+sub+"\""
        end
        return $textbar.script.parse("gosub",sub,"gosub "+sub)  
      else
        return nil
      end
    end
    def SpeechScript.ExecCmd(line)
      if line.index("#")==nil and line!=""
        line=$textbar.script.replaceVariables(line)
        if line.index(" ")!=nil and line.slice(0,1)!="\""
          cmd=line.slice(0,line.index(" "))
          args=line.slice(line.index(" "),line.length-line.index(" "))
          args=$textbar.script.splitArgs(args)
        else
          cmd=line
          args=[]
        end
        return $textbar.script.parse(cmd.strip,args,line)
      end
      return nil
    end
    def SpeechScript.ExecScript(script)
      $textbar.loadText(script)
    end
  end
end

end



class ObjectScript
  def initialize(file="null.rb",*classes)
    if File.file?(file)
      @file=File.new(file)
      @file.close
    end
    @classes={}
    if classes!=nil
      classes.each { |klass|
        @classes[klass.name]=klass
      }
    end
    @objects=[]
    @found=[]
    @inobjdef=false
    @objdeftype=nil
    @lno=0
  end
  
  def setFile(file)
    if @file!=nil and not @file.closed?
      @file=File.new(file)
      @file.close
      return true
    else
      return false
    end
  end
  
  def reset
    @classes={}
    @objects=[] 
    @found=[]
    @inobjdef=false
    @objdeftype=nil
    @lno=0
  end
  
  def clearAcceptedClasses
    @classes={}   
  end
  
  def addAcceptedClass(objectclass)
    @classes[objectclass.name]=objectclass
  end

  def run
    @file.reopen(@file.path)
    @objects=[]
    workobj=ObjectInstance.new
    @file.each { |line|
      @lno+=1
      if line.index("//")
        line.slice!(0, line.index("//")+2)
      end
      line.strip!
      if not line=="" 
        lines=line.split(";")
        lines.each { |line|
          line.strip!
          if line.index(" ")
            line=[line.slice(0,line.index(" ")), line.slice(line.index(" ")+1,line.size-(line.index(" ")+1))]
          end
          ret=parse(line)
          if ret==true
            @objects.push(workobj)
            workobj=ObjectInstance.new
          elsif ret!=nil
            workobj.setType(@objdeftype.to_sym) if workobj.type==nil
            workobj.addProperty(ret[0],ret[1])
          end
        }
      end
    }
    @file.close
    return @objects
  end

  #def eachObject()
  #  
  #end

  def parse(line) 
    if @inobjdef
      if line.kind_of?(Array)
        if @classes[@objdeftype].hasProperty?(line[0])
          if line.size>2 and @classes[@objdeftype].getProperty(line[0])[:type] != :array
            ExtraTokens.warn(@file.path, @lno)
          end
          prop=@classes[@objdeftype].getProperty(line[0])
          if prop==false
            BadPropery.error(@file.path, @lno, line[0], @objdeftype.to_s)
          elsif @found.index(prop)!=nil and not prop[:allowmult]
            MultDeclarations.error(@file.path, @lno, line[0])
          elsif not prop[:allowmult]
            @found.push(prop)
          end
          type=prop[:type]
          if type===:string
            return [line[0], getString(line[1])]
          elsif type===:int
            return [line[0], getNum(line[1])]
          elsif type===:array
            return [line[0], getArray(prop, line[1])]
          elsif type===:enumerated
            return [line[0], getEnumed(prop, line[1])]
          elsif type===:any
            return [line[0], line[1]]
          end
        else
          BadParam.error(@file.path, @lno, line[0])          
        end
      elsif line=="end"
        @inobjdef=false
        @found=[]
        return true
      else
        ExpectedVal.error(@file.path, @lno, line) 
      end
    else
      if line.kind_of?(Array)
        ExpectedClass.error(@file.path, @lno)
      end
      if @classes.has_key?(line.to_sym)
        @inobjdef=true  
        @objdeftype=line.to_sym
      else
        BadClass.error(@file.path, @lno, line)
      end
    end
    return nil
  end
  
  def getString(data)
    if data.slice(0,1)=="$"
      data.gsub!("_"," ")
      data.gsub!("\\n","\n")
      data.gsub!("\\t","\t")
      data.gsub!("\\sm",";")
      data.gsub!("\\ds","//")
      data.gsub!("\\us","_")
      data.gsub!("\\cm",",")
      data.subVars!
      data=data.slice(1,data.size-1)
    elsif data.slice(0,1)=="\"" or data.slice(0,1)=="'"
      index=data.index("\"")
      index=data.index("\'") if index==nil
      index=data.size-1
      data=data.slice(1,index-1)
      data.gsub!("\\n","\n")
      data.gsub!("\\t","\t")
      data.gsub!("\\sm",";")
      data.gsub!("\\ds","//")
      data.gsub!("\\us","_")
      data.gsub!("\\dq","\"")
      data.gsub!("\\sq","'")
      data.gsub!("\\cm",",")
      data.subVars!
    end
    return data
  end
  
  def getNum(data)
    return data.to_i
  end
  
  def getArray(property,data)
    data=data.split(",")
    max=property[:"max values"]
    min=property[:"min values"]
    if max!=-1 and data.size > max
      TooManyArgs.warn(@file.path, @lno, max)
      data=data.first(max)
    elsif min!=-1 and data.size < min
      puts data.size
      puts data
      puts
      raise TooFewArgs.error(@file.path, @lno, min)
      return nil
    end
    type=property[:"value type"]
    i=0
    data.each { |val|
      data[i]=val.strip
      i+=1
    }
    if type===:any
      
    elsif type===:string
      i=0
      data.each { |val|
        data[i]=getString(val)
        i+=1
      }
    elsif type===:int
      i=0
      data.each { |val|
        data[i]=getNum(val)
        i+=1
      }      
 #   elsif type==:enumerated
  #    i=0
  #    data.each { |val|
 #       data[i]=getEnumed(data)
 #       i+=1
 #     }         
    end
    return data
  end
  
  def getEnumed(property,data)
    vals=property[:"enum values"]
    if vals.index(data)!=nil
      return data
    else
      BadEnum(@file.path, @lno, data)
      return nil
    end
  end
  
class ObjectClass
  attr_reader :name
  def initialize(name="")
    @name=name.to_sym
    @map={}
  end
  def addStringProperty(name,manditory=true,allowmultiple=false)
    property={:type=>:string}
    return addProperty(name, property,manditory,allowmultiple)
  end
  def addIntProperty(name,manditory=true,allowmultiple=false)
    property={:type=>:int}
    return addProperty(name, property,manditory,allowmultiple)
  end
  def addArrayProperty(name,maxvalues=-1,minvalues=-1,valtype=:any,manditory=true,allowmultiple=false)
    property={:type=>:array}
    property[:"value type"]=valtype
    property[:"max values"]=maxvalues
    property[:"min values"]=minvalues
    return addProperty(name, property,manditory,allowmultiple)
  end
  #def addEnumArrayProperty(name,values,maxvalues=-1,minvalues=-1,valtype=:any,manditory=true,allowmultiple=false)
  #  
  #end
  def addEnumProperty(name,values,manditory=true,allowmultiple=false)
    property={:type=>:enumerated}
    property[:"enum values"]=values
    return addProperty(name, property,manditory,allowmultiple)
  end
  def addProperty(name,property,manditory,allowmultiple)
    property[:mand]=manditory
    property[:allowmult]=allowmultiple
    if name===:string or name===:int or name===:any or @map.has_key?(name)
      return false
    end
    @map[name]=property
    return true
  end
  def getProperty(property)
    if @map.has_key?(property)
      return @map[property]  
    else
      return false
    end
  end
  def hasProperty?(property)
    return @map.has_key?(property)
  end
end

class ObjectInstance
  attr_reader :properties, :values, :type
  def initialize(type=nil)
    @type=type
    @properties=[]
    @values=[]
  end
  def setType(type)
    @type=type
  end
  def addProperty(name,value)
    @properties.push(name)
    @values.push(value)
  end
  def each
    i=0
    @properties.each { |name|
      yield name, @values[i]
    }
  end
  def eachof(property)
    i=0
    @properties.each { |name|
      yield @values[i] if name==property
      i+=1
    }
  end
  def [](name)
    if @properties.index(name)!=nil
      return @values[@properties.index(name)]
    end
    return nil
  end
  def hasProperty?(name)
    return @properties.index(name)!=nil
  end
  def getProperty(name)
    if @properties.index(name)!=nil
      return @values[@properties.index(name)]
    end
    return nil
  end
end

end

end #module Dataparse

include Dataparse
